<!-- 一维碰撞 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>一维碰撞</title>
    <style>
        canvas {
            background-color: black;
        }
    </style>
</head>

<body>
    <canvas id="canvas"></canvas>
</body>
<script src="../utils.js"></script>
<script>
    // 小球绘制
    class Ball {
        constructor(options) {
            this.x = 0;
            this.y = 0;
            this.r = 200;
            this.fillStyle = 'blue';
            this.strokeStyle = 'black';
            // 小球缩放
            this.scaleX = 1;
            this.scaleY = 1;
            // 定义小球移动速度
            this.vx = 0;
            this.vy = 0;
            // 小球透明度
            this.alpha = 1;
            Object.assign(this, options);
            return this;
        }
        render(ctx) {
            let { x, y, r, fillStyle, strokeStyle, scaleX, scaleY, alpha } = this;
            // 保存绘图环境
            ctx.save();
            // 开始绘制
            // ctx.beginPath();
            ctx.beginPath();
            ctx.translate(x, y);
            ctx.scale(scaleX, scaleY);
            ctx.strokeStyle = strokeStyle;
            ctx.fillStyle = fillStyle;

            ctx.globalAlpha = alpha;

            ctx.arc(0, 0, r, 0, Math.PI * 2);


            ctx.fill();
            ctx.stroke();
            ctx.restore();
            ctx.closePath();
            return this;
        }
        // 判断点是否在图形内部
        isInside(x, y) {
            let dis = Math.sqrt(Math.pow(x - this.x, 2) + Math.pow(y - this.y, 2))
            return dis < this.r;
        }
    }

    let canvas = document.getElementById('canvas');
    let ctx = canvas.getContext('2d');
    let w = canvas.width = 800;
    let h = canvas.height = 800;

    // 实例化两个小球，用于碰撞
    let ball = new Ball({
        x: 100,
        y: h / 2,
        r: 40,
        fillStyle: 'red',
        strokeStyle: 'black',
        vx: 3,
        m: 1 // 质量
    });
    let ball2 = new Ball({
        x: w - 100,
        y: h / 2,
        r: 60,
        fillStyle: 'blue',
        strokeStyle: 'black',
        vx: -4,
        m: 2 // 质量
    });

    /**
     * 绘制线
     * @returns 
     */
    function drawLine() {
        ctx.save();
        ctx.beginPath();
        ctx.lineTo(0, h / 2);
        ctx.lineTo(w, h / 2);
        ctx.strokeStyle = 'pink';
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.restore();
    }

    (function move() {
        window.requestAnimationFrame(move);
        ctx.clearRect(0, 0, w, h);

        drawLine();
        ball.x += ball.vx;
        ball2.x += ball2.vx;
        // 小球碰撞检测
        // 两个小球距离
        let dis = Math.abs(ball.x - ball2.x);
        if (dis <= ball.r + ball2.r) {
            // 重置位置，防止小球有重叠部分
            let lep = ball.r + ball2.r - dis;
            ball.x = ball.x - lep / 2;
            ball2.x = ball2.x + lep / 2;

            ball.vx = ((ball.m - ball2.m) * ball.vx + 2 * ball2.m * ball2.vx) / (ball.m + ball2.m);
            ball2.vx = ((ball2.m - ball.m) * ball2.vx + 2 * ball.m * ball.vx) / (ball.m + ball2.m);
        }

        ball.render(ctx);
        ball2.render(ctx);
    })()

</script>

</html>